<!--
@description    自定义筛选条件
@author         秦俊强
@email          458112865@qq.com
@create         2021-06-13


@Examples & Step

1. import CustomScreen from './customScreen';

2. components: { CustomScreen }

3. 使用 customScreenRef 可自定义
   下面是 2 种使用方法示例（* 详细请查看 192 行 props 里面的说明）

    3.1 默认空，手动添加自定义筛选项
    <CustomScreen ref="customScreenRef"></CustomScreen>

    3.2 回填信息，编辑漏斗时，默认填充数据
    <CustomScreen ref="customScreenRef" :supName="'$AppClick'"
                  :editArr="{ conditions: [ 'field': '', 'function': '', "params": [] ], relation: 'or' }"></CustomScreen>

4. 添加一行
    => this.$refs.customScreenRef.editCond();

5. 返回传参需要的 filter 对象
    => this.$refs.customScreenRef.getFilterConditions();
-->

<template>
  <div class="viewFunnelBox" :style="{ padding: '5px 0' }" v-if="arrSetting.length > 0">

    <!-- 【且】【或】切换 -->
    <div class="andOrNotBox" v-if="arrSetting.length > 1"
         @click="switchRelation">{{ relation.name }}</div>

    <!-- 线 -->
    <div class="lineBox" :style="{ height: getLineHeight() }"
         v-if="arrSetting.length > 1"></div>

    <!-- 动态添加自定义筛选项 start -->
    <div class="funnelSettingBox" v-for="(item, i) in arrSetting" :key="i">

      <!-- 1. 一级（主）下拉选项 start -->
      <el-select size="mini" @change="settingChange(i)" placeholder="请选择"
                 :title="arrSetting[i].cname"
                 filterable value-key="name"
                 v-model="arrSetting[i]">
        <el-option v-for="cItem in levelOneOpts"
                   :key="cItem.name" :value="cItem" :disabled="cItem.isDisabled"
                   :style="{ 'max-width': '600px' }"
                   :label="cItem.cname" :title="cItem.cname"></el-option>
      </el-select>
      <!-- 1. 一级（主）下拉选项 end -->



      <!-- 2. 二级下拉选项，根据（一级）不同的 data_type 显示不同的下拉选项 start -->
      <el-select size="mini" :style="{ width: '150px' }"
                 v-if="arrSetting[i] && arrSetting[i].name"
                 v-model="arrSetting[i]['new_data_type']" value-key="key"
                 @change="dataTypeChange(i)">
        <el-option v-for="cItem in getDataTypeOpts(i)"
                   :key="cItem.key" :value="cItem" :label="cItem.name"></el-option>
      </el-select>
      <!-- 2. 二级下拉选项，根据（一级）不同的 data_type 显示不同的下拉选项 end -->



      <!-- 3.1 可输入多个值（数字或字符串）start -->
      <el-select v-if="showLeaf(i, 'createCommon')" size="mini" placeholder="输入内容后，按回车可添加多个"
                 v-model="arrSetting[i]['customArr']" :style="{ width: '40%' }"
                 @change="$forceUpdate()"
                 multiple filterable allow-create default-first-option clearable>
        <el-option v-for="(cItem, ind) in lastOptsMap[item.name]"
                   :key="ind" :value="cItem" :label="cItem"></el-option>
      </el-select>
      <!-- 3.1 可输入多个值（数字或字符串）end -->

      <!-- 3.2 可输入单个值 start -->
      <el-input v-if="showLeaf(i, 'inputCommon')" size="mini" placeholder="请输入内容"
                v-model="arrSetting[i]['customStr']" :style="{ width: '40%' }" clearable></el-input>
      <!-- 3.2 可输入单个值 end -->

      <!-- 3.3 数字区间 start -->
      <div class="betweenBox" v-if="showLeaf(i, 'numBetween')">
        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumBetween_0']"
                  :style="{ width: '110px' }" clearable></el-input>

        <span style="padding: 0 5px;">与</span>

        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumBetween_1']"
                  :style="{ width: '110px' }" clearable></el-input>

        <span style="padding: 0 5px;">之间</span>
      </div>
      <!-- 3.3 数字区间 end -->

      <!-- 3.4.1 日期区间 yyyy-mm-dd 00:00 至 yyyy-mm-dd 00:00 -->
      <el-date-picker v-if="showLeaf(i, 'autoDateBetween')"
                      format="yyyy-MM-dd 00:00" value-format="yyyy-MM-dd 00:00"
                      type="daterange"  size="mini" range-separator="至"
                      start-placeholder="开始日期" end-placeholder="结束日期"
                      :picker-options="pickerOptions" style="width: 280px;"
                      v-model="arrSetting[i]['customAutoDateBetween']"></el-date-picker>

      <!-- 3.4.2 相对当前时间点，在 n 天 以内/以外 -->
      <div class="datetimeBox" v-if="showLeaf(i, 'relativeWithin')">
        <span class="size">在</span>

        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumDate']"
                  :style="{ width: '100px', paddingRight: '5px' }" clearable></el-input>

        <span class="size">天</span>

        <el-select size="mini" :style="{ width: '90px' }"
                   v-model="arrSetting[i]['customRelative']" value-key="key"
                   @change="$forceUpdate()">
          <el-option v-for="cItem in datetimeOpts[1].arr"
                     :key="cItem.key" :value="cItem" :label="cItem.name"></el-option>
        </el-select>
      </div>

      <!-- 3.4.3 相对当前时间区间，在过去xx到过去xx之内 -->
      <div class="datetimeBox" v-if="showLeaf(i, 'dayBetween')">
        <span class="size">在过去</span>

        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumDate_0']"
                  :style="{ width: '100px', paddingRight: '5px' }" clearable></el-input>

        <span class="size">天到过去</span>

        <el-input size="mini" type="number" placeholder="请输入数字"
                  v-model="arrSetting[i]['customNumDate_1']"
                  :style="{ width: '100px', paddingRight: '5px' }" clearable></el-input>

        <span class="size">天之内</span>
      </div>

      <!-- 3.4.4 相对当前事件发生时间 在【之前/后/当天/当周/当月】的【n】【天/时/分/秒】之内 -->
      <div class="datetimeBox" v-if="showLeaf(i, 'eventTime')">
        <span class="size">在</span>

        <el-select size="mini" :style="{ width: '110px' }"
                   v-model="arrSetting[i]['customEventTime']" value-key="key"
                   @change="$forceUpdate()">
          <el-option v-for="cItem in relativeEventTime"
                     :key="cItem.key" :value="cItem" :label="cItem.name"></el-option>
        </el-select>

        <span>
          <span class="size">的</span>

          <el-input size="mini" type="number" placeholder="请输入数字"
                    v-model="arrSetting[i]['customNumDate_2']"
                    :style="{ width: '100px', paddingRight: '5px' }" clearable></el-input>

          <el-select size="mini" :style="{ width: '90px' }"
                     v-model="arrSetting[i]['customTimeUnit']" value-key="key"
                     @change="$forceUpdate()">
            <el-option v-for="cItem in timeUnit" :key="cItem.key" :value="cItem" :label="cItem.name"></el-option>
          </el-select>

          <span>之内</span>
        </span>
      </div>



      <!-- 移除筛选项 -->
      <i class="el-icon-delete" title="移除筛选项" @click="editCond(i)"></i>

    </div>
    <!-- 动态添加自定义筛选项 end -->

  </div>
</template>


<script>
  /* dataType 类型配置 */
  import DataTypeConfig from './dataType.config.js';

  /**
   * api 接口
   * */
  import { propertyList, valueList } from './api.config.js';



  export default {
    name: 'custom-screen',

    props: {
      /**
       * 是否有父级（默认无，可直接调用全部接口）
       * 如果有，则需要传下面的 supName 参数才能调用接口
       * */
      isSupName: {
        type: Boolean,
        default: () => { return false; }
      },

      /**
       * 上级 name，如：'$AppClick'
       * 用于创建/编辑漏斗时，根据上级 name 动态获取子级下拉选项
       *
       * 可传，可不传（默认空）
       * */
      supName: {
        type: String,
        default: () => { return ''; }
      },

      /**
       * 编辑漏斗时需要传的参数，用于回填信息
       * 注意：编辑漏斗时，上面的 supName 字段必传
       * 默认值 { conditions: [], relation: '' }
       * */
      editArr: {
        type: Object,
        default: () => {
          return {
            conditions: [
              /*{ "field": "$distinct_id", "function": "equal", "params": ['a', 'b', 'c'] },
              { "field": "$time", "function": "absolute_between", "params": ["2021-06-01 00:00", "2021-06-09 00:00"] },
              { "field": "$element_position", "function": "notContain", "params": "100" },*/
            ],

            relation: 'or',       // 且 and | 或 or，conditions length 大于 1 时 relation 不可为空
          };
        }
      }
    },

    data() {
      return {
        /* 一级下拉项 */
        levelOneOpts: [],

        /* 叶子节点的下拉选项 */
        lastOptsMap: {},

        /* data_type 为 bool 时选，没有 3 级信息 */
        boolOpts: DataTypeConfig.boolOpts,

        /* data_type 为 string 时选 */
        textOpts: DataTypeConfig.textOpts,

        /* data_type 为 number 时选 */
        numberOpts: DataTypeConfig.numberOpts,

        /* data_type 为 datetime 时选  */
        datetimeOpts: DataTypeConfig.datetimeOpts,

        /* data_type 为 list 时选 */
        listOpts: DataTypeConfig.listOpts,

        /* 且 and | 或 or */
        relation: { key: 'and', name: '且' },

        /* 日期选择器，不能选择今天以后的日期 */
        pickerOptions: {
          disabledDate(time) {
            return time.getTime() > Date.now() - 8.64e6;
          }
        },

        /* 相对事件发生时间 选项 */
        relativeEventTime: DataTypeConfig.relativeEventTime,

        /* 时间单位 选项 */
        timeUnit: DataTypeConfig.timeUnit,

        /* 自定义筛选 */
        arrSetting: [],

      }
    },

    created() {
      let t = this;
      t.getFunnelCondition();

      /* 监听 supName 变化 */
      t.$watch('supName', () => {
        console.log('****** supName is change，重置自定义筛选项，根据 supName 的值获取对应的子级下拉列表');
        t.arrSetting = [{}];
        t.getFunnelCondition();
      });
    },

    methods: {

      /* 回填 数据 */
      initData() {
        let t = this;
        let conditions = t.editArr.conditions;
        let relation = t.editArr.relation;
        for (let i = 0; i < conditions.length; i++) {
          let item = conditions[i];

          t.editCond();
          t.initLevelOne(item, i);
        }

        t.switchRelation(relation);
        t.initDisabled();

        setTimeout(() => { this.$forceUpdate(); });
      },

      /* 回填 一级下拉选项 */
      initLevelOne(item, ind) {
        for (let i = 0; i < this.levelOneOpts.length; i++) {
          let _item = this.levelOneOpts[i];

          let f = item.field, n = _item.name;
          let fArr = f.split(".");
          let nArr = n.split(".");

          if (fArr[fArr.length - 1] === nArr[nArr.length - 1]) {
            this.arrSetting[ind] = _item;
            this.initLevelTwo(item, ind);
            return;
          }
        }
      },

      /* 回填 二级下拉菜单 */
      initLevelTwo(item, ind) {
        let opts = this.getDataTypeOpts(ind);

        for (let i = 0; i < opts.length; i++) {
          let _item = opts[i];

          if (item['function'] === _item.key) {
            this.arrSetting[ind]['new_data_type'] = _item;

            this.initLevelThree(item, ind);
            return;
          }
        }
      },

      /* 回填 三级下拉菜单 */
      initLevelThree(item, ind) {
        let _item = this.arrSetting[ind];
        let objMap = DataTypeConfig.rules;

        for (let key in objMap) {
          let obj = objMap[key];

          let arr1 = obj.dataTypeArr;
          let arr2 = obj.newDataTypeArr;

          if (arr1.indexOf(_item.dataType) >= 0 && arr2.indexOf(_item['new_data_type'].key) >= 0) {

            if (obj.key === 'customArr') {
              this.getValueList(ind, item.params);
              return;
            }

            this.arrSetting[ind][obj.key] = item.params;
            return;

          }
        }
      },

      /* 监听一级（主）筛选条件项 */
      settingChange(i) {
        this.initCustomVal(i);
        this.initDisabled();

        this.getValueList(i);

        this.$forceUpdate();  // 强制刷新组件数据
      },

      /* 监听二级下拉筛选 */
      dataTypeChange(i) {
        let obj = this.arrSetting[i];
        console.log('监听二级筛选项 = ', i, obj);

        this.initCustomVal(i);

        this.$forceUpdate();  // 强制刷新组件数据
      },

      /* 切换【且】【或】 */
      switchRelation(val) {
        let valMap = {
          or: { key: 'or', name: '或' },
          and: { key: 'and', name: '且' },
        };

        if (val && valMap[val]) {
          this.relation = valMap[val];
          return;
        }

        let key = this.relation.key;
        this.relation = (key === 'and') ? { key: 'or', name: '或' } : { key: 'and', name: '且' };
      },

      /* 判断显示哪个三级选项 */
      showLeaf(i, str) {
        let obj = this.arrSetting[i];
        let dataType = obj['dataType'];                 // 一级 type
        let newDataType = obj['new_data_type'];         // 二级 type

        // 如果没有选择一级或二级，那么就隐藏三级
        if (!dataType || !newDataType || !newDataType.key) { return false; }

        // 显示条件
        let objMap = DataTypeConfig.rules;

        // 可自定义多个值，敲回车进行添加值 的组件
        if (objMap[str]) {
          let dataTypeArr = objMap[str].dataTypeArr;
          let newDataTypeArr = objMap[str].newDataTypeArr;

          return (dataTypeArr.indexOf(dataType) >= 0) && (newDataTypeArr.indexOf(newDataType.key) >= 0);
        }

        return false;
      },

      /* 添加 add | 移除 remove 筛选条件 */
      editCond(i) {
        // 移除筛选条件
        if (typeof i === 'number') {
          this.arrSetting.splice(i, 1);
          this.initDisabled();
          return;
        }

        // 添加筛选项
        this.arrSetting.push({});
        this.initCustomVal();

        // 默认【且】
        if (this.arrSetting.length === 2) {
          this.relation = { key: 'and', name: '且' };
        }
      },

      /* 初始化自定义字段（三级项）的值 */
      initCustomVal(ind) {
        let t = this;

        setTimeout(() => {
          let arrSetting = t.arrSetting;

          let _ind = (typeof ind === 'number') ? ind : (arrSetting.length - 1);

          if (arrSetting[_ind]['customArr'] && arrSetting[_ind]['customArr'].length > 0) {
            t.arrSetting[_ind]['customArr'] = [];    //数组
          }

          if (arrSetting[_ind]['customStr']) {
            t.arrSetting[_ind]['customStr'] = '';    //对象
          }

          if (arrSetting[_ind]['customNumBetween_0'] || arrSetting[_ind]['customNumBetween_1']) {
            t.arrSetting[_ind]['customNumBetween_0'] = '';
            t.arrSetting[_ind]['customNumBetween_1'] = '';
          }
        });
      },

      /* 筛选项不可选设置 */
      initDisabled() {
        let arrSetting = this.arrSetting;

        for (let i = 0; i < this.levelOneOpts.length; i++) {
          let item = this.levelOneOpts[i];

          this.levelOneOpts[i]['isDisabled'] = false;

          for (let j = 0; j < arrSetting.length; j++) {
            let cItem = arrSetting[j];

            if (this.levelOneOpts[i]['isDisabled']) { continue; }

            if (item.name === cItem.name) {
              this.levelOneOpts[i]['isDisabled'] = true;
            }
          }
        }
      },

      /* 根据父级 data type 返回子级下拉选项 */
      getDataTypeOpts(i) {
        let dataType = this.arrSetting[i].dataType;

        let objKey = {
          'string': 'textOpts',
          'number': 'numberOpts',
          'bool': 'boolOpts',
          'datetime': 'datetimeOpts',
          'list': 'listOpts',
        };

        if (objKey[dataType]) { return this[objKey[dataType]]; }

        return [];
      },

      /* 返回计算线条高度 */
      getLineHeight() {
        let len = this.arrSetting.length;

        if (len < 2) { return 0; }
        if (len === 2) { return '38px'; }
        return ((len - 2) * 38 + 38) + 'px';
      },

      getParams(item) {
        let objMap = DataTypeConfig.rules;  //显示组件

        for (let key in objMap) {
          let obj = objMap[key];

          let arr1 = obj.dataTypeArr;
          let arr2 = obj.newDataTypeArr;

          if (arr1.indexOf(item.dataType) >= 0 && arr2.indexOf(item['new_data_type'].key) >= 0) {
            if (typeof obj.key === 'string') { return item[obj.key]; }

            let arr3 = [];
            for (let i = 0; i < obj.key.length; i++) {
              let k = obj.key[i];

              if (item[k].key) {
                arr3.push(item[k].key);
              } else {
                arr3.push(item[k]);
              }
            }

            return arr3;
          }
        }

        return false;
      },

      /* 返回自定义筛选项 */
      getFilterConditions() {
        let arr = [];
        let arrSetting = this.arrSetting;

        if (!arrSetting || arrSetting.length === 0) { return {}; }

        for (let i = 0; i < arrSetting.length; i++) {
          let item = arrSetting[i];

          if (!item.name || !item['new_data_type'] || !item['new_data_type'].key) { continue; }

          let param = {
            "field": item.name,
            "function": item['new_data_type'].key,
          };

          let params = this.getParams(item);
          if (params) { param['params'] = params; }

          arr.push(param);
        }

        if (arrSetting.length === 1) { return { conditions: arr }; }

        return {
          conditions: arr,
          relation: this.relation.key,       // 且 | 或
        }
      },

      /* 获取一级下拉菜单选项（默认） */
      getFunnelCondition() {
        let t = this;

        /* 如果需要父级，却没有传父级，不需要调用接口 */
        if (t.isSupName && !t.supName) { return; }

        let param = {
          events: t.isSupName ? t.supName : '_Anything',
          type: 'event',
          needEventTime: true
        };

        propertyList(param).then((res) => {
          // 返回状态码如果不是 200，说明数据异常，需弹窗提示
          if (res.data.code !== 200) {
            this.$alert(res.data.msg, '提示', { type: 'warning'});
            return;
          }

          t.levelOneOpts = res.data.data.rows;
          if (t.editArr.conditions.length > 0) { t.initData(); }
        }).catch((error) => {
          console.log('error = ', error);
        });
      },

      /* 通过已选一级的值，获取三级下拉选项 */
      getValueList(i, arr) {
        let t = this;
        let setting = t.arrSetting[i];
        let k = setting.name;

        if (setting.dataType !== 'string') { return; }

        let param = {
          event: 'event._Anything.' + setting.name,
          appId: JSON.parse(window.sessionStorage.getItem('appItem')).appId
        };
        console.log(JSON.parse(window.sessionStorage.getItem('appItem')).appId)
        valueList(param).then((res) => {
          // 返回状态码如果不是 200，说明数据异常，需弹窗提示
          if (res.data.code !== 200) {
            this.$alert(res.data.msg, '提示', { type: 'warning'});
            return;
          }

          t.lastOptsMap[k] = res.data.data.rows;

          if (t.isArray(arr)) {
            t.lastOptsMap[k] = this.MergeArray(t.lastOptsMap[k], arr);
            this.arrSetting[i]['customArr'] = arr;
          }

          t.$forceUpdate();  // 强制刷新组件数据
        })
            .catch((error) => {
          t.lastOptsMap[k] = [];
          console.log('error = ', error);
        });
      },

      isArray(a) {
        return (Object.prototype.toString.call(a) === '[object Array]');
      },

      /* 数组去重 */
      MergeArray(arr1, arr2) {
        let _arr = new Array();

        for (let i = 0; i < arr1.length; i++) { _arr.push(arr1[i]); }

        for (let i = 0; i < arr2.length; i++) {
          let flag = true;

          for (let j = 0; j < arr1.length; j++) {
            if (arr2[i] == arr1[j]) {
              flag = false;
              break;
            }
          }

          if (flag) { _arr.push(arr2[i]); }
        }

        return _arr;
      },

    },

  }
</script>



<style scoped lang="scss">
  .viewFunnelBox {
    padding: 10px 0;
    border-bottom: 1px solid #e7e7e7;
    position: relative;

    button { height: 27px; }

    .title-size {
      display: inline-block;
      width: 80px;
      padding: 0 10px;
      text-align: right;
    }

    .el-select { margin-right: 10px; }
  }

  .funnelSettingBox {
    border-left: 2px solid #6FD3B3 ;
    padding: 5px 0 5px 97px;
    position: relative;

    &:hover { background-color: #fafafa; }

    input[type='number'] { padding-right: 0; }

    .el-select {margin-right: 10px;}

    .size { padding-right: 5px;}

    .betweenBox,
    .datetimeBox { display: inline-block; }
  }

  i.el-icon-delete {
    position: absolute;
    right: 20px;
    top: 50%;
    transform: translate(0, -50%);
    cursor: pointer;

    &:hover { color: rgb(247, 86, 94); }
  }

  .andOrNotBox,
  .lineBox {
    position: absolute;
    top: 50%;
  }

  /* 且或非 */
  .andOrNotBox {
    width: 26px;
    height: 26px;
    font-size: 12px;
    text-align: center;
    line-height: 26px;
    border: 1px solid #cccccc;
    background-color: #fafafa;
    border-radius: 3px;
    cursor: pointer;
    z-index: 10;
    transform: translate(46px, -50%);
  }

  .lineBox {
    width: 26px;
    border: 1px solid #cccccc;
    border-right: none;
    transform: translate(60px, -50%);
    z-index: 5;
  }
</style>
